#pragma once

#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include "tcpServer.hpp"
#include "nocopy.hpp"
class tcpServer;
class connection;
class connectContainer;
using func_t = std::function<void(std::shared_ptr<connection>)>;

class connection : public std::enable_shared_from_this<connection>
{
public:
    connection() {}
    ~connection() {}
    connection(int fd, std::shared_ptr<tcpServer> svr, func_t readBk, func_t writeBk, func_t excptBk)
        : _fd(fd), _readBk(readBk), _writeBk(writeBk), _excptBk(excptBk), _svrPtr(svr) {}

    int getFd() { return _fd; }
    void read() { _readBk(shared_from_this()); }
    void write() { _writeBk(shared_from_this()); }
    void except() { _excptBk(shared_from_this()); }
    void locate(const std::string &ip, const uint16_t &port)
    {
        _ip = ip;
        _port = port;
    }
    std::string &inbuffer() { return _inBuffer; }
    std::string &outbuffer() { return _outBuffer; }

private:
    int _fd;
    std::string _inBuffer;
    std::string _outBuffer;
    func_t _readBk;
    func_t _writeBk;
    func_t _excptBk;
    std::string _ip;
    std::string _port;
    //////////////
public:
    std::weak_ptr<tcpServer> _svrPtr;
};

class connectContainer : public nocopy
{
public:
    connectContainer() {}
    ~connectContainer()
    {
        lg(Info, "connectContainer delete done");
    }
    connectContainer(const std::shared_ptr<tcpServer> &svr)
        : _tcpServer(svr) {}
    bool addConnection(int fd, func_t readBk, func_t writeBk, func_t excptBk)
    {
        if (_connections.count(fd))
            return false;
        // 注意，这里直接使用make_shared有问题，会导致当前对象被两个不同权限组的shared_ptr共同管理导致西沟两次，所以要有enable_shared_from_this
        std::shared_ptr<connection> newCon(new connection(fd, _tcpServer, readBk, writeBk, excptBk));
        _connections[fd] = newCon;
        lg(Info, "add new connection done, fd:%d", fd);
        return true;
    }
    bool delConnection(int fd)
    {
        if (_connections.count(fd) == 0)
            return false;
        _connections.erase(fd);
        return true;
    }
    void printOnlineList()
    {
        std::cout << "now online socket: ";
        for (const auto &[fd, con] : _connections)
            std::cout << fd << ' ';
        std::cout << std::endl;
    }
    std::shared_ptr<connection> at(int i) { return _connections[i]; }
    bool isSafeFd(int fd) { return _connections.count(fd); }

private:
    std::unordered_map<int, std::shared_ptr<connection>> _connections;
    std::shared_ptr<tcpServer> _tcpServer;
};